/*
**  File: AquaFuncts_nmrstar.c
**
**  This file is part of the AQUA program suite, which is being
**  developed in the NMR Spectroscopy Department, Bijvoet Center for 
**  Biomolecular Research, Utrecht. 
**
**
**  AUTHOR(S) : Ton Rullmann
**  VERSION   : 1.0
**  DATE      : Feb 17, 1997
**
**  Update    : Jurgen F. Doreleijers
**  VERSION   : BMRB development
**  DATE      : May 8, 2000
**  DONE      : Updated the output for NMR-STAR format for distance constraints.
**
**  This file contains routines for handling NMR-STAR files.
**
**  Most header definitions are present in AquaFuncts_io.c
*/

/****************  function prototypes  ****************/

#include "AquaFuncts_nmrstar.h"

/****************  globals  ****************/
extern char     *project_name;                 /* import from AquaFuncts */

/* BEGIN_EXTH */


/****************  Write_star  ****************/
/*
**  Write an NMR-STAR file, either a single model: the model with number <model>, 
**  or all models: if <model> equals 0.
**  The used tags are still under development.
**  Assumption right now is that the chain ID can be transfered to the
**  molecule system component name....
**  Routine modified from Write_pdb
**
**  Limitations:
**  1) Insertion codes can not be handled
**  2) Atom type can not be derived
**
**  JFD @ Fri May 12 17:15:46 CDT 2000
*/

Boolean Write_star( FILE *fp, Strucset *set, const int model, Boolean wrmodel )
{
    Struc   *strucptr;
    Coord   *coordptr;
    Mol     *molptr = set->molecule;
    Atom    *atomptr;
    int     count, num = 0, extra_spaces;
    ID      temp_atom_name;
                    
    fprintf( fp, "data_%s_coordinates\n", project_name);
    fprintf( fp, "\n");
    fprintf( fp, "save_conformer_family_%s\n", project_name);
    fprintf( fp, "   _Saveframe_category        structure_coordinate_set\n");
    fprintf( fp, "\n");
    fprintf( fp, "   _Details\n");
    fprintf( fp, ";\n");
    fprintf( fp, "   @\n");
    fprintf( fp, ";\n");
    fprintf( fp, "\n");
    fprintf( fp, "   loop_\n");
    fprintf( fp, "      _Experiment_label\n");
    fprintf( fp, "\n");
    fprintf( fp, "      @\n");
    fprintf( fp, "\n");
    fprintf( fp, "   stop_\n");
    fprintf( fp, "\n");
    fprintf( fp, "   loop_\n");
    fprintf( fp, "      _Sample_label\n");
    fprintf( fp, "\n");
    fprintf( fp, "      @\n");
    fprintf( fp, "\n");
    fprintf( fp, "   stop_\n");
    fprintf( fp, "\n");
    fprintf( fp, "   _Sample_conditions_label  @\n");
    fprintf( fp, "\n");
    fprintf( fp, "   loop_\n");
    fprintf( fp, "      _Constraint_list_label\n");
    fprintf( fp, "\n");
    fprintf( fp, "      @\n");
    fprintf( fp, "\n");
    fprintf( fp, "   stop_\n");
    fprintf( fp, "\n");
    fprintf( fp, "   loop_\n");
    fprintf( fp, "      _Atom_ID\n");
    fprintf( fp, "      _Conformer_number\n");
    fprintf( fp, "      _Mol_system_component_name\n");
    fprintf( fp, "      _Residue_seq_code\n");
    fprintf( fp, "      _Residue_label\n");
    fprintf( fp, "      _Atom_name\n");
    fprintf( fp, "      _Atom_type\n");
    fprintf( fp, "      _Atom_coord_x\n");
    fprintf( fp, "      _Atom_coord_y\n");
    fprintf( fp, "      _Atom_coord_z\n");
    fprintf( fp, "        \n");

                
    if ( set->struc_count > 1 && !model )
	wrmodel = true;
    strucptr = set->fst_struc;
    while ( strucptr )
    {
	if ( !model || strucptr->struc_num == model )
	{
                            
	    count = set->atom_count;
	    coordptr = strucptr->coords;
	    atomptr = molptr->atoms;
            
	    while ( count-- )
	    {                
		fprintf( fp, "      %7d ", ++num );
		fprintf( fp, "%4d ", strucptr->struc_num );
                                
		if ( ( atomptr->chain[0] == ' ' ) || 
                     ( atomptr->chain[0] == '_' ) ) {
                    fprintf( fp, " .  ");
                } else {
                    FPrintChars( fp, atomptr->chain, 4 );
                }

		fprintf( fp, " %4d ", atomptr->res_num_orig );
                
                FPrintChars( fp, atomptr->res_nam,  4 );
		fprintf( fp, " ");                        

                /* atom name */
                if ( Has_single_quote(  atomptr->atom_int ) ) {
                    fprintf( fp, "\"");
                    CopyChars(temp_atom_name, atomptr->atom_int, size_ID);
                    RemLeadSpc(temp_atom_name, size_ID);
                    FPrintChars( fp, temp_atom_name, LenChars(temp_atom_name, size_ID) );
                    fprintf( fp, "\"");
                    extra_spaces = 5 - LenChars(temp_atom_name, size_ID);
                    while ( extra_spaces-- ) {
                        fprintf( fp, " ");
                    }
                } else {
                    fprintf( fp, " ");
                    FPrintChars( fp, atomptr->atom_int,  4 );
                    fprintf( fp, "  ");
                }

                /* atom element symbol */
                if ( ( atomptr->atom_element_symbol[0] == ' ' ) && 
                     ( atomptr->atom_element_symbol[1] == ' ' ) ) {
                    fprintf( fp, " . ");
                } else {
                    fprintf( fp, " ");
                    FPrintChars( fp, atomptr->atom_element_symbol,  2 );
                }
                                
		fprintf( fp, " %8.3f %8.3f %8.3f\n", 
		    coordptr->x, 
                    coordptr->y,
                    coordptr->z );

                if ( atomptr->res_insert != ' ' ) {
                        fprintf( fp, "ERROR: Found insertion code: %c\n", atomptr->res_insert);
                        printf( "ERROR: Found insertion code: %c\n", atomptr->res_insert);
                        return( false );
                }
                                
                coordptr++;
		atomptr++;
	    }
	}
        strucptr = strucptr->next_struc;
    }    
    
    fprintf( fp, "          \n");
    fprintf( fp, "   stop_\n");
    fprintf( fp, "\n");
    fprintf( fp, "save_\n");
    fprintf( fp, "\n");    
    
    return( true );
}





/****************  WriteRestraints_nmrstar  ****************/
/*
**  Write restraints in NMR-STAR restraint format. 
*/

#define size_KEY 80

Boolean WriteRestraints_nmrstar( FILE *fp, DRestraint *DR_list, const int DR_count, 
                            int skip_count, Card ident, char *DR_typ, 
			    char *Mol_label )
{
    char        *fct_name = "WriteRestraints_nmrstar";
    char        key[size_KEY], empty_chain[size_ID];
    DRestraint  *restrs;
    Boolean     use_chain = false;
    char        *dot = "    .   ";
    int         count;

    Blank( empty_chain, size_ID );
    CopyChars( empty_chain, "  .", size_ID );

/* check whether we need _mol_entity_code, and whether insertion codes are present */

    restrs = DR_list;
    count = DR_count;
    while ( count-- )
    {
	if ( !restrs->keep ) 
	{
	    restrs++;
	    continue;
	}
	if ( LenChars( restrs->atom_A.chain, size_ID ) ||
	     LenChars( restrs->atom_B.chain, size_ID )    )
	{
	    use_chain = true;
	}
	if ( ( restrs->atom_A.res_insert != ' ' ) ||
	     ( restrs->atom_B.res_insert != ' ' )    )
	{
	    printf( " * Residue insertion code(s) present - can't handle yet\n" );
	    return( false );
	}
	restrs++;
    }

/* the save frame name is composed from the DR type and the Mol_label */

    strcpy( key, DR_typ );
    ToUpperStr( key );
    fprintf( fp, "data_distance_constraints_%s_%s\n", key, Mol_label );
    fprintf( fp, "\n" );
    fprintf( fp, "save_distance_constraints_%s_%s\n", key, Mol_label );
    fprintf( fp, "   _Saveframe_category   distance_constraints\n\n" );

    fprintf( fp, "   loop_\n" );

    fprintf( fp, "      _Atom_one_mol_system_component_name\n" );
    fprintf( fp, "      _Atom_one_residue_seq_label\n" );
    fprintf( fp, "      _Atom_one_residue_seq_code\n" );
    fprintf( fp, "      _Atom_one_atom_name\n" );

    fprintf( fp, "      _Atom_two_mol_system_component_name\n" );
    fprintf( fp, "      _Atom_two_residue_seq_label\n" );
    fprintf( fp, "      _Atom_two_residue_seq_code\n" );
    fprintf( fp, "      _Atom_two_atom_name\n" );

    fprintf( fp, "      _Distance_value\n" );
    fprintf( fp, "      _Distance_upper_bound_value\n" );
    fprintf( fp, "      _Distance_lower_bound_value\n\n" );

    restrs = DR_list;
    count = DR_count;
    while ( count-- )
    {
	if ( !restrs->keep ) 
	{
	    restrs++;
	    continue;
	}

	fprintf( fp, "   " );

	if ( !LenChars( restrs->atom_A.chain, size_ID ) )
	    FPRINTID( fp, empty_chain );
	else
	    FPRINTID( fp, restrs->atom_A.chain );

	if ( !LenChars( restrs->atom_A.res_nam, size_ID ) )
	    FPRINTID( fp, empty_chain ); 
        /* empty_chain is misused here but who cares */        
	else
	    FPRINTID( fp, restrs->atom_A.res_nam );        

        fprintf( fp, " %3i ", restrs->atom_A.res_num_orig );
	FPRINTID( fp, restrs->atom_A.atom_ext );

	fprintf( fp, "   " );

	if ( !LenChars( restrs->atom_B.chain, size_ID ) )
	    FPRINTID( fp, empty_chain );
	else
	    FPRINTID( fp, restrs->atom_B.chain );

	if ( !LenChars( restrs->atom_B.res_nam, size_ID ) )
	    FPRINTID( fp, empty_chain ); 
	else
	    FPRINTID( fp, restrs->atom_B.res_nam );        
        
	fprintf( fp, " %3i ", restrs->atom_B.res_num_orig );
	FPRINTID( fp, restrs->atom_B.atom_ext );

	switch( restrs->stat )
	{
	    case bnd_upper:
		fprintf( fp, " %s %8.3f %s\n", dot, restrs->up_bnd, dot );
		break;
	    case bnd_lower:
		fprintf( fp, " %s %s %8.3f\n", dot, dot, restrs->lo_bnd );
		break;
	    case bnd_uplo:
		fprintf( fp, " %s %8.3f %8.3f\n", dot, restrs->up_bnd, restrs->lo_bnd );
		break;
	    case bnd_uld:
		fprintf( fp, " %8.3f %8.3f %8.3f\n", restrs->dist, restrs->up_bnd, restrs->lo_bnd );
		break;
	    default:
		FATAL( "wrong data type" );
	}
		
	restrs++;
    }
    fprintf( fp, "   stop_\n\n" );
    fprintf( fp, "save_\n\n" );
    
    return( true );
}

#undef size_KEY

/* Checks if there is any single quote character in the ID  */

Boolean Has_single_quote ( ID atom_name ) 
{        
    if ( memchr ( atom_name, '\'', size_ID ) ) {
	return ( true );
    } else {
        return ( false );
    }
}
